package com.hsjk.szwj.module.pay.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hsjk.szwj.framework.common.constant.CommonConstant;
import com.hsjk.szwj.framework.common.exception.ServiceException;
import com.hsjk.szwj.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.hsjk.szwj.module.pay.api.IMchDivisionReceiverApi;
import com.hsjk.szwj.module.pay.api.dto.MchDivisionReceiverDTO;
import com.hsjk.szwj.module.pay.constant.PayOrderConstant;
import com.hsjk.szwj.module.pay.constant.PayOrderDivisionConstant;
import com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg;
import com.hsjk.szwj.module.pay.dal.dataobject.config.PayOrderDivisionMQ;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDO;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDivisionRecordDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchAppDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchInfoDO;
import com.hsjk.szwj.module.pay.util.AmountUtil;
import com.hsjk.szwj.module.train.api.ICheckoutOrderApi;
import com.hsjk.szwj.module.train.api.IOrderApi;
import com.hsjk.szwj.module.train.api.ISkuDivisionApi;
import com.hsjk.szwj.module.train.api.dto.CheckoutOrderDTO;
import com.hsjk.szwj.module.train.api.dto.DivisionReceiverDTO;
import com.hsjk.szwj.module.train.api.dto.OrderDTO;
import com.hsjk.szwj.module.train.api.dto.UpdateCheckoutOrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenjiawei
 * @desc 业务： 支付订单分账处理逻辑
 * @Date 2023/08/25 01:30
 **/
@Slf4j
@Component
public class PayOrderDivisionProcessService {

    @Resource
    private PayOrderService payOrderService;
    @Resource
    private MchDivisionReceiverService mchDivisionReceiverService;
    @Resource
    private MchDivisionReceiverGroupService mchDivisionReceiverGroupService;
    @Resource
    private PayOrderDivisionRecordService payOrderDivisionRecordService;
    @Resource
    private ConfigContextQueryService configContextQueryService;
    @Resource
    private PayInterfaceDefineService payInterfaceDefineService;
    @Resource
    private IMchInfoService mchInfoService;
    @Resource
    private IMchAppService mchAppService;

    @Resource
    private IOrderApi orderApi;

    @Resource
    private ICheckoutOrderApi checkoutOrderApi;

    @Resource
    private ISkuDivisionApi skuDivisionApi;

    @Resource
    private IMchDivisionReceiverApi mchDivisionReceiverApi;


    /**
     * 处理分账，
     * 1. 向外抛异常： 系统检查没有通过 / 系统级别异常
     * 2 若正常调起接口将返回渠道侧响应结果
     *
     * @param payOrderId
     * @param useSysAutoDivisionReceivers
     * @param receiverList
     * @param isResend
     * @return com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg
     * @author chenjiawei
     * @date 2023/11/6 5:42 PM
     **/
    public ChannelRetMsg processPayOrderDivision(Long payOrderId,
                                                 Integer useSysAutoDivisionReceivers,
                                                 List<PayOrderDivisionMQ.CustomerDivisionReceiver> receiverList,
                                                 Boolean isResend) {
        // 是否重发分账接口（ 当分账失败， 列表允许再次发送请求 ）
        if (isResend == null) {
            isResend = false;
        }


        String logPrefix = "订单[" + payOrderId + "]执行分账";
        log.info("processPayOrderDivision:" + logPrefix);

        //查询订单信息
        PayOrderDO payOrder = payOrderService.getById(payOrderId);

        if (payOrder == null) {
            log.error("{}，订单不存在", logPrefix);
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "订单不存在");
        }

        // 分账状态不正确
        if (payOrder.getDivisionState() != PayOrderConstant.DIVISION_STATE_WAIT_TASK
                && payOrder.getDivisionState() != PayOrderConstant.DIVISION_STATE_UNHAPPEN) {
            log.error("{}, 分账状态不正确", logPrefix);
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "分账状态不正确");
        }

        //更新订单为： 分账任务处理中
        boolean updPayOrder = payOrderService.update(new LambdaUpdateWrapper<PayOrderDO>()
                .set(PayOrderDO::getDivisionState, PayOrderConstant.DIVISION_STATE_ING)
                .eq(PayOrderDO::getId, payOrderId)
                .eq(PayOrderDO::getDivisionState, payOrder.getDivisionState()));
        if (!updPayOrder) {
            log.error("{}, 更新支付订单为分账处理中异常！", logPrefix);
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "更新支付订单为分账处理中异常");
        }

        //查询订单信息
        OrderDTO orderdto = orderApi.getOrderInfoByOrderNo(String.valueOf(payOrder.getMchOrderId()));

        // 所有的分账列表
        List<PayOrderDivisionRecordDO> recordList = null;

        // 重发通知，可直接查库
        if (isResend) {
            // 根据payOrderId && 待分账（ 重试时将更新为待分账状态 ）  ， 此处不可查询出分账成功的订单。
            recordList = payOrderDivisionRecordService.list(new LambdaQueryWrapper<PayOrderDivisionRecordDO>()
                    .eq(PayOrderDivisionRecordDO::getPayOrderId, payOrderId)
                    .eq(PayOrderDivisionRecordDO::getState, PayOrderDivisionConstant.STATE_WAIT));
        } else {

            // 查询&过滤 所有的分账接收对象
            List<DivisionReceiverDTO> allReceiver =
                    this.queryReceiver(orderdto.getSkuId(), orderdto.getId());
            DivisionReceiverDTO divisionReceiverItem = allReceiver.get(0);
            //获取
            log.info("processPayOrderDivision:allReceiver:{}", allReceiver);
            Long subDivisionAmount = 0L;
            //计算分账金额 = 商家实际入账金额
            Long payOrderDivisionAmount = payOrderService.calMchIncomeAmount(payOrder, divisionReceiverItem);

            if (CommonConstant.DIVISION_MODEL_AMOUNT.equals(divisionReceiverItem.getDivisionModel())) {
                Long allDivisionAmount = 0L;
                for (DivisionReceiverDTO receiver : allReceiver) {
                    allDivisionAmount += receiver.getDivisionAmount();
                }
                subDivisionAmount = payOrderDivisionAmount - allDivisionAmount;
            } else if (CommonConstant.DIVISION_MODEL_PERCENTAGE.equals(divisionReceiverItem.getDivisionModel())) {
                //得到全部分账比例 (所有待分账账号的分账比例总和)
                BigDecimal allDivisionProfit = BigDecimal.ZERO;
                for (DivisionReceiverDTO receiver : allReceiver) {
                    allDivisionProfit = allDivisionProfit.add(receiver.getDivisionProfit());
                }
                //剩余待分账金额 (用作最后一个分账账号的 计算， 避免出现分账金额超出最大) [结果向下取整 ， 避免出现金额溢出的情况。 ]
                subDivisionAmount = AmountUtil.calPercentageFee(payOrderDivisionAmount,
                        allDivisionProfit, BigDecimal.ROUND_FLOOR);
            }
            log.info("processPayOrderDivision:subDivisionAmount:{}", subDivisionAmount);

            recordList = new ArrayList<>();

            //计算订单分账金额, 并插入到记录表


            for (DivisionReceiverDTO receiver : allReceiver) {

                PayOrderDivisionRecordDO record = genRecord(
                        payOrder, receiver, payOrderDivisionAmount, subDivisionAmount, divisionReceiverItem.getDivisionModel());

                //剩余金额
                subDivisionAmount = subDivisionAmount - record.getCalDivisionAmount();

                //入库保存
                payOrderDivisionRecordService.save(record);
                recordList.add(record);
            }
        }


        ChannelRetMsg channelRetMsg = null;

        try {
            String ifCode = payInterfaceDefineService.getCodeById(payOrder.getIfId());
            //调用渠道侧分账接口
            IDivisionService divisionService =
                    SpringUtil.getBean(ifCode + "DivisionService",
                            IDivisionService.class);
            if (divisionService == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "通道无此分账接口");
            }
            MchInfoDO mchInfoDO = mchInfoService.getMchInfoById(payOrder.getMchId());
            MchAppDO mchAppDO = mchAppService.getById(payOrder.getAppId());
            log.info("processPayOrderDivision-recordList:{}", recordList);
            channelRetMsg = divisionService.singleDivision(payOrder, recordList,
                    configContextQueryService
                            .queryMchInfoAndAppInfo(mchInfoDO.getId(), mchAppDO.getId()));

            // 确认分账成功 ( 明确分账成功 )
            if (channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {

                //分账成功
                payOrderDivisionRecordService.updateRecordSuccessOrFail(recordList, PayOrderDivisionConstant.STATE_SUCCESS,
                        channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelOriginResponse());
                //更改结算单状态
                handleDivision(recordList);
            } else if (channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL) {
                //分账失败
                payOrderDivisionRecordService.updateRecordSuccessOrFail(recordList, PayOrderDivisionConstant.STATE_FAIL,
                        channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrMsg());


            } else if (channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.WAITING) {
                // 已受理
                payOrderDivisionRecordService.updateRecordSuccessOrFail(recordList, PayOrderDivisionConstant.STATE_ACCEPT,
                        channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrMsg());
            }

        } catch (Exception e) {

            log.error("{}, 调用分账接口异常", logPrefix, e);
            payOrderDivisionRecordService.updateRecordSuccessOrFail(recordList,
                    PayOrderDivisionConstant.STATE_FAIL,
                    null, "系统异常：" + e.getMessage());

            channelRetMsg = ChannelRetMsg.confirmFail(null, null, e.getMessage());
        }

        //更新 支付订单主表状态  分账任务已结束。
        payOrderService.update(new LambdaUpdateWrapper<PayOrderDO>()
                .set(PayOrderDO::getDivisionState, PayOrderConstant.DIVISION_STATE_FINISH)
                .set(PayOrderDO::getDivisionLastTime, LocalDateTime.now())
                .eq(PayOrderDO::getId, payOrderId)
                .eq(PayOrderDO::getDivisionState, PayOrderConstant.DIVISION_STATE_ING)
        );

        return channelRetMsg;
    }

    private void handleDivision(List<PayOrderDivisionRecordDO> recordList) {
        log.info("handleDivision:{}", recordList);
        if (CollUtil.isNotEmpty(recordList)) {
            for (PayOrderDivisionRecordDO recordDO : recordList) {
                UpdateCheckoutOrderDTO updateCheckoutOrderDTO = new UpdateCheckoutOrderDTO();
                updateCheckoutOrderDTO.setId(recordDO.getId());
                updateCheckoutOrderDTO.setStatus(CommonConstant.SETTLEMENT_STATUS_SETTLED);
                checkoutOrderApi.updateCheckoutOrderStatusById(updateCheckoutOrderDTO);
            }
        }
    }

    /**
     * 生成对象信息
     **/
    private PayOrderDivisionRecordDO genRecord(PayOrderDO payOrder,
                                               DivisionReceiverDTO receiver,
                                               Long payOrderDivisionAmount,
                                               Long subDivisionAmount, Integer divisionModel) {

        PayOrderDivisionRecordDO record = new PayOrderDivisionRecordDO();
        record.setMchOrderNo(payOrder.getMchOrderId());
        record.setMchId(payOrder.getMchId());
        record.setIsvId(payOrder.getIsvId());
        record.setAppId(payOrder.getAppId());
        record.setMchName(payOrder.getMchName());
        record.setMchType(payOrder.getMchType());
        record.setIfId(payOrder.getIfId());
        record.setPayOrderId(payOrder.getId());
        //支付订单渠道订单号
        record.setPayOrderChannelOrderNo(payOrder.getChannelOrderNo());
        //订单金额
        record.setPayOrderAmount(payOrder.getAmount());
        // 订单计算分账金额
        record.setPayOrderDivisionAmount(payOrderDivisionAmount);
        //系统分账批次号
        record.setBatchOrderId(String.valueOf(receiver.getBatchOrderId()));
        //状态: 待分账
        record.setState(PayOrderDivisionConstant.STATE_WAIT);
        record.setReceiverId(receiver.getId());
        record.setReceiverGroupId(receiver.getReceiverGroupId());
        record.setReceiverAlias(receiver.getReceiverAlias());
        record.setAccType(receiver.getAccType());
        record.setAccNo(receiver.getAccNo());
        record.setAccName(receiver.getAccName());
        record.setRelationType(receiver.getRelationType());
        record.setRelationTypeName(receiver.getRelationTypeName());
        record.setDivisionProfit(receiver.getDivisionProfit());
        record.setDivisionModel(receiver.getDivisionModel());
        record.setDivisionAmount(receiver.getDivisionAmount());

        if (subDivisionAmount <= 0) {
            record.setCalDivisionAmount(0L);
        } else {
            //计算的分账金额
            if (CommonConstant.DIVISION_MODEL_PERCENTAGE.equals(divisionModel)) {
                record.setCalDivisionAmount(AmountUtil.calPercentageFee(record.getPayOrderDivisionAmount(), receiver.getDivisionProfit()));
            } else if (CommonConstant.DIVISION_MODEL_AMOUNT.equals(divisionModel)) {
                record.setCalDivisionAmount(receiver.getDivisionAmount());
            }
            if (record.getCalDivisionAmount() > subDivisionAmount) {
                // 分账金额超过剩余总金额时： 将按照剩余金额进行分账。
                record.setCalDivisionAmount(subDivisionAmount);
            }
        }
        return record;
    }


    private List<DivisionReceiverDTO> queryReceiver(Long skuId, Long orderNo) {
        List<DivisionReceiverDTO> skuDivisionListBySkuId = skuDivisionApi.getSkuDivisionListBySkuId(skuId);
        if (CollUtil.isNotEmpty(skuDivisionListBySkuId)) {
            for (DivisionReceiverDTO dto : skuDivisionListBySkuId) {
                MchDivisionReceiverDTO mchDivisionReceiver = mchDivisionReceiverApi.getMchDivisionReceiverById(dto.getMchDivisionReceiverId());
                if (ObjectUtil.isNotNull(mchDivisionReceiver)) {
                    dto.setId(mchDivisionReceiver.getId());
                    dto.setReceiverAlias(mchDivisionReceiver.getReceiverAlias());
                    dto.setAccNo(mchDivisionReceiver.getAccNo());
                    dto.setAccName(mchDivisionReceiver.getAccName());
                    dto.setRelationType(mchDivisionReceiver.getRelationType());
                    dto.setAccType(mchDivisionReceiver.getAccType());
                    dto.setReceiverGroupId(mchDivisionReceiver.getReceiverGroupId());
                    dto.setRelationTypeName(mchDivisionReceiver.getRelationTypeName());
                }
                CheckoutOrderDTO checkoutOrder = checkoutOrderApi.getCheckoutOrderByDivisionReceiverId(dto.getMchDivisionReceiverId(), orderNo);
                if (ObjectUtil.isNotNull(checkoutOrder)) {
                    dto.setBatchOrderId(checkoutOrder.getId());
                }
            }
        }
        return skuDivisionListBySkuId;
//        String ifCode = payInterfaceDefineService.getCodeById(payOrder.getIfId());
//        // 查询全部分账列表
//        LambdaQueryWrapper<MchDivisionReceiverDO> queryWrapper = new LambdaQueryWrapper<MchDivisionReceiverDO>();
//
//        //mchNo
//        queryWrapper.eq(MchDivisionReceiverDO::getMchId, payOrder.getMchId());
//        //appId
//        queryWrapper.eq(MchDivisionReceiverDO::getAppId, payOrder.getAppId());
//        //ifCode
//        queryWrapper.eq(MchDivisionReceiverDO::getIfCode, ifCode);
//        // 可用状态的账号
//        queryWrapper.eq(MchDivisionReceiverDO::getState, CommonConstant.PUB_USABLE);
//
//        // 自动分账组的账号
//        if (CommonConstant.YES.equals(useSysAutoDivisionReceivers)) {
//            MchInfoDO mchInfoById = mchInfoService.getMchInfoById(payOrder.getMchId());
//            List<MchDivisionReceiverGroupDO> groups = mchDivisionReceiverGroupService.list(
//                    new LambdaQueryWrapper<MchDivisionReceiverGroupDO>()
//                            .eq(MchDivisionReceiverGroupDO::getMchNo, mchInfoById.getMchNo())
//                            .eq(MchDivisionReceiverGroupDO::getAutoDivisionFlag, CommonConstant.YES));
//
//            if (groups.isEmpty()) {
//                return new ArrayList<>();
//            }
//
//            queryWrapper.eq(MchDivisionReceiverDO::getReceiverGroupId,
//                    groups.get(0).getId());
//        }
//
//        //全部分账账号
//        List<MchDivisionReceiverDTO> allMchReceiver =
//                mchDivisionReceiverService.list(queryWrapper);
//        if (allMchReceiver.isEmpty()) {
//            return allMchReceiver;
//        }
//
//        //自动分账组
//        if (CommonConstant.YES.equals(useSysAutoDivisionReceivers)) {
//            return allMchReceiver;
//        }

        //以下为 自定义列表

        // 自定义列表未定义
//        if (customerDivisionReceiverList == null || customerDivisionReceiverList.isEmpty()) {
//            return new ArrayList<>();
//        }
//
//        // 过滤账号
//        List<MchDivisionReceiverDO> filterMchReceiver = new ArrayList<>();
//
//        for (MchDivisionReceiverDO mchDivisionReceiver : allMchReceiver) {
//            for (PayOrderDivisionMQ.CustomerDivisionReceiver customerDivisionReceiver
//                    : customerDivisionReceiverList) {
//
//                // 查询匹配相同的项目
//                if (mchDivisionReceiver.getId().equals(customerDivisionReceiver.getReceiverId()) ||
//                        mchDivisionReceiver.getReceiverGroupId().equals(customerDivisionReceiver.getReceiverGroupId())
//                ) {
//
//                    // 重新对分账比例赋值
//                    if (customerDivisionReceiver.getDivisionProfit() != null) {
//                        mchDivisionReceiver.setDivisionProfit(customerDivisionReceiver.getDivisionProfit());
//                    }
//                    filterMchReceiver.add(mchDivisionReceiver);
//                }
//            }
//        }
//
//        return filterMchReceiver;
    }

    public static void main(String[] args) {
        Long l = AmountUtil.calPercentageFee(200L, new BigDecimal("0.2"));
        System.out.println(l);
    }
}

